//*********************************************************
//
//    Copyright (c) Microsoft. All rights reserved.
//    This code is licensed under the Apache License, Version 2.0.
//    THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
//    ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
//    IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
//    PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//*********************************************************

using System;
using System.ComponentModel;
using System.Workflow.ComponentModel;
using Microsoft.Research.ScientificWorkflow.Helper;

namespace Microsoft.Research.ScientificWorkflow.Activities
{
    /// <summary>
    /// This OpenDAPProjection activity class supports adding projections
    /// to the Open DAP query.
    /// The Open Dap files contain variables and their corresponding data
    /// values. The variables are the projections which allow querying  
    /// values for the variable.
    /// Projections are added to the opendap uri after the file name by
    /// appending a '?'
    /// for e.g. the url
    /// http://plasmus.ocean.washington.edu:8080/opendap/ROMS/HC_bio_seasonal_nowind_his_0800.nc.ascii?ntimes
    /// fetches values for only the ntimes variable.
    /// </summary>
    [Name("OpenDap Projections Builder")]
    [Description("Constructs the projection clauses in the query. The clauses are added to the query string before executing on the server.")]
    [WorkflowCategory("OpenDap")]
    class OpenDAPProjection : Activity
    {
        #region Property Definitions

        public static DependencyProperty InputDAPUriProperty = DependencyProperty.Register("InputDAPUri",
            typeof(OpenDAPURI), typeof(OpenDAPProjection));

        /// <summary>
        /// Input Open DAP Uri generated after appending the server name
        /// and the file name.
        /// </summary>
        [RequiredInputParam]
        [Name("Input Open DAP Uri")]
        [Description("Input Open DAP Uri for adding the projections.")]
        public OpenDAPURI InputDAPUri
        {
            get { return ((OpenDAPURI)(base.GetValue(OpenDAPProjection.InputDAPUriProperty))); }
            set { base.SetValue(OpenDAPProjection.InputDAPUriProperty, value); }
        }

        public static DependencyProperty VariablesProperty = DependencyProperty.Register("Variables",
            typeof(string), typeof(OpenDAPProjection));

        /// <summary>
        /// Comma seperated variables to be read from the server. The format is
        /// varialbname1,type1,variablename2,type2
        /// The type exepeted here is OpenDAPURI.DapVariableType.
        /// </summary>
        [RequiredInputParam]
        [Name("Open DAP Variable Names")]
        [Description("Name of the variables from the Open DAP file.")]
        public string Variables
        {
            get { return ((string)(base.GetValue(OpenDAPProjection.VariablesProperty))); }
            set { base.SetValue(OpenDAPProjection.VariablesProperty, value); }
        }

        public static DependencyProperty OutputDAPUriProperty = DependencyProperty.Register("OutputDAPUri",
            typeof(OpenDAPURI), typeof(OpenDAPProjection));

        /// <summary>
        /// Input Open DAP Uri generated after appending the server name
        /// and the file name.
        /// </summary>
        [OutputParam]
        [Name("Output Open DAP Uri")]
        [Description("Output Open DAP Uri with projections.")]
        public OpenDAPURI OutputDAPUri
        {
            get { return ((OpenDAPURI)(base.GetValue(OpenDAPProjection.OutputDAPUriProperty))); }
            set { base.SetValue(OpenDAPProjection.OutputDAPUriProperty, value); }
        }

        #endregion

        #region Overridden methods

        /// <summary>
        /// This method reads the variables and adds the same to the 
        /// input uri and then assigns the new uri to the output.
        /// </summary>
        /// <param name="executionContext"></param>
        /// <returns></returns>
        protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext)
        {
            // Parse the variables property to read the variable names
            // and the corresponding types.
            string[] names;
            OpenDAPURI.DapVariableType[] types;
            ParseVariables(out names, out types);

            // Add the variables to the DAP URI.
            for (int i = 0; i < names.Length; ++i)
            {
                this.InputDAPUri.AddVariable(names[i], types[i]);
            }

            this.OutputDAPUri = this.InputDAPUri;
            return ActivityExecutionStatus.Closed;
        }

        #endregion

        #region Private Methods

        /// <summary>
        /// This method parses the Variables property to read the variable names
        /// and the corresponding types.
        /// Throws an error if there are inconsistencies.
        /// </summary>
        private void ParseVariables(out string[] names, out OpenDAPURI.DapVariableType[] types)
        {
            if(string.IsNullOrEmpty(this.Variables))
                throw new ArgumentException("Required input parameter not set.");

            string[] v = (this.Variables).Split(new char[] { ',' });
            if (v.Length % 2 != 0)
                throw new ArgumentException("Error Converting from String to Variable Array");

            names = new string[v.Length / 2];
            types = new OpenDAPURI.DapVariableType[v.Length / 2];

            for (int i = 0, j = 0; i < v.Length; j++)
            {
                names[j] = v[i];
                types[j] = (OpenDAPURI.DapVariableType)
                    Enum.Parse(typeof(OpenDAPURI.DapVariableType), v[i + 1]);
                i = i + 2;
            }
        }

        #endregion
    }
}
